package com.example.boot6rabbitmq.consumer;


import com.rabbitmq.client.Channel;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.support.AmqpHeaders;
import org.springframework.messaging.handler.annotation.Header;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * 消费者
 */
@Component
public class MessageConsumer {
    int i = 0;

    //    可以配置消费者的一些信息，比如手动确认，最大的消费者数 ConsumeConfig
    //,containerFactory = "qos_4"
    @RabbitListener(queues = "chenfl.message")
    //@RabbitListener(queues = "chenfl.message")
    public void topicAccep (String message, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag){
        System.out.println("deliveryTag=>"+deliveryTag);
        try {
            //故意方消费失败
            //为测试第7点最后一个，将异常注释掉
             //int b=1/0;


            System.out.println("MessageConsumer topic received message : " +message);
            channel.basicAck(deliveryTag,false);
            System.out.println("---进行手动确认完成！---");
        } catch (Exception e) {
            try {

                //前提为手动确认
                //当消费失败的时候如果是下列代码，则会把数据放回到队列，然后服务端会不停的发过来
//                i = 1;
//                System.out.println("此时i等于......=>"+i);
//                channel.basicNack(deliveryTag,false,true);

                //当消费失败时后，如果什么都不管的话，消息就有一个unacked状态就会堆积在服务上,当服务重启时候消息的状态会变成ready的状态就会去消费，如果消费失败还是会记录状态
                System.out.println("此时i等于1.。。");

                //当大前提改为自动提交的时候，如果消费失败，消息就会丢失，如果不做报错记录的话

                //参考参考
                //https://www.jianshu.com/p/ec5d9b966f2e
                //throw new RuntimeException(e);
                /*
                 1、监听的方法内部必须使用channel进行消息确认，包括消费成功或消费失败
                    2、如果不手动确认，也不抛出异常，消息不会自动重新推送（包括其他消费者），因为对于rabbitmq来说始终没有接收到消息消费是否成功的确认，并且Channel是在消费端有缓存的，没有断开连接

//3.如果消费端应用重启，消息会自动重新推送
//4.不管抛异常与否 只要消费端处理消息的时候宕机，消息会自动推给其他的消费者
6、如果监听消息的方法抛出异常，消息会按照listener.retry的配置进行重发，但是重发次数完了之后还抛出异常的话，消息不会重发（也不会重发到其他消费者），只有应用重启后会重新推送。因为retry是消费端内部处理的，包括异常也是内部处理，对于rabbitmq是不知道的（此场景解决方案后面有）
7、spring.rabbitmq.listener.retry配置的重发是在消费端应用内处理的，不是rabbitqq重发

                 */

                //测试配置retry  注释掉自己写的配置类，在yml中配置的就会生效，只会配几次重试几次，而且重试最后一次完成之后，才会继续抛出异常
                throw new RuntimeException(e);

            } catch (Exception ex) {
                throw new RuntimeException(ex);
            }
        }
    }

    @RabbitListener(queues = "chenfl.message1")
    public void topicAccept (String message){
        System.out.println(" 1 topic received message : " +message);
    }
}
